package com.beikai.elasticsearch_demo.api.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSONObject;
import com.beikai.elasticsearch_demo.api.dao.UserDao;
import com.beikai.elasticsearch_demo.api.service.UserService;
import com.beikai.elasticsearch_demo.model.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.experimental.Accessors;
import org.assertj.core.util.Lists;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.Clock;
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2020-02-09 22:57:58
 */
@Service("userService")
public class UserServiceImpl implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
    @Resource
    private UserDao userDao;

    @Autowired
    RestHighLevelClient restHighLevelClient;


    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public User queryById(Integer id) {
        return this.userDao.queryById(id);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit  查询条数
     * @return 对象列表
     */
    @Override
    public List<User> queryAllByLimit(int offset, int limit) {
        return this.userDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User insert(User user) {
        this.userDao.insert(user);
        return user;
    }

    @Test
    public void test() {
        List<String> ids = Lists.newArrayList("1_0", "5_0", "9_0");

        for (int i = 0; i < 5; i++) {
            System.out.println("前---------------" + ids.toString() + "---------------");
            for (int j = 0; j < ids.size(); j++) {
                String id = ids.get(j);
                System.out.println(id);
                // 保存的id 是以 保单主键_发送次数 格式
                String[] tempIds = id.split("_");
                // 保单主键
                long tempId = Long.parseLong(tempIds[0]);
                // 发送次数
                int num = Integer.parseInt(tempIds[1]);
                if (2 == num) {
                    // 如果已经发送三次，不再发送
                    continue;
                }

                if (5L == tempId && num == 1) {
                    ids.remove(j);
                    j--;
                    continue;
                }

                if (1L == tempId) {
                    ids.remove(j);
                    j--;
                    continue;
                }

                // 发送失败，发送次数为 加1
                ids.remove(j);
                num++;
                ids.add(tempId + "_" + num);
                j--;
            }

            System.out.println("后---------------" + ids.toString() + "---------------");
        }
    }

    @Test
    public void test02() {
        String stll = null;
        stll = "zhangsna";
        User user = new User();
        user.setAddress("zhangsan");
        Optional.ofNullable(user).flatMap(each -> Optional.ofNullable(each.getAddress())).orElse("lisi");

    }

    @Test
    public void test03() {
        Clock clock = Clock.systemUTC();
        System.out.println("click : " + clock.millis());


        Clock clock1 = Clock.systemDefaultZone();
        System.out.println("click1 : " + clock1.millis());


        LocalDate of = LocalDate.of(2020, 02, 23);
        System.out.println(of);


        LocalDate minus = of.minus(1, ChronoUnit.DAYS);
        System.out.println(minus);


        if (minus.isLeapYear()) {
            System.out.println(true);
        }

        Period between = Period.between(of, LocalDate.now());
        System.out.println(between.getDays());

    }

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User update(User user) {
        this.userDao.update(user);
        return this.queryById(user.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.userDao.deleteById(id) > 0;
    }

    @Override
    public JSONObject getInfo(Integer num, Integer size) {

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        handlePage(sourceBuilder, num, size);

        // 添加查询条件  模糊搜索
        //sourceBuilder.query(QueryBuilders.matchQuery("content", "小蜜蜂"));
        // 使用分词器
        sourceBuilder.query(QueryBuilders.matchQuery("content", "蜜蜂").analyzer("ik_smart"));
        // 设置高亮"
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("content");
        highlightBuilder.preTags("<span >");
        highlightBuilder.postTags("</ span>");
        sourceBuilder.highlighter(highlightBuilder);

        // 查询全部
        //sourceBuilder.query(QueryBuilders.matchAllQuery());

        // 设置超时时间
        SearchRequest rq = new SearchRequest();

        // 设置 要查询的索引
        rq.indices("tel_message");
        //各种组合条件
        rq.source(sourceBuilder);

        //请求
        //System.out.println(rq.source().toString());
        try {
            SearchResponse search = restHighLevelClient.search(rq, RequestOptions.DEFAULT);
            //System.out.println(search);

            List<Map<String,Object>> list = Lists.newArrayList();

            for (SearchHit hit : search.getHits()) {

                Map<String, HighlightField> highlightFields =
                        hit.getHighlightFields();

                HighlightField content = highlightFields.get("content");

                Map<String, Object> sourceAsMap = hit.getSourceAsMap();

                // 解析高亮的字段,把原来的字段换成高亮的字段
                if (null != content) {
                    Text[] fragments = content.getFragments();
                    String n_content = "";
                    for (Text fragment : fragments) {
                        n_content += fragment;
                    }
                    sourceAsMap.put("content",n_content);
                }

                list.add(sourceAsMap);

                System.out.println(hit.getSourceAsString());
            }


            
            return getResult(list);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return getResult("暂无数据!");
    }

    @Override
    public JSONObject addIndex(String indexName) throws IOException {

        try {
            // 创建 Mapping
            XContentBuilder mapping = XContentFactory.jsonBuilder();

            // 创建 es 字段
            mapping.startObject();
            {
                mapping.startObject("properties");
                {
                    mapping.startObject("message");
                    {
                        mapping.field("type", "text");
                    }
                    mapping.endObject();

                    mapping.startObject("name");
                    {
                        mapping.field("type", "text");
                    }
                    mapping.endObject();

                    mapping.startObject("address");
                    {
                        mapping.field("type", "text");
                    }
                    mapping.endObject();

                    mapping.startObject("age");
                    {
                        mapping.field("type", "text");
                    }
                    mapping.endObject();
                }
                mapping.endObject();
            }
            mapping.endObject();

            // 配置分片信息，配置
            Settings settings = Settings.builder()
                    .put("index.number_of_shards", 3)
                    .put("index.number_of_replicas", 2)
                    .build();

            CreateIndexRequest request = new CreateIndexRequest(indexName);
            request.mapping(mapping);
            request.settings(settings)
            ;

            request.alias(new Alias("new_user").filter(QueryBuilders.termQuery("name","zhansan")));

            // RestHighLevelClient 执行创建索引
            CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
            // 判断是否创建成功
            boolean isCreated = createIndexResponse.isAcknowledged();
            log.info("是否创建成功：{}", isCreated);
        } catch (IOException e) {
            log.error("", e);
        }

        return getResult(true);
    }

    @Override
    public JSONObject addUser() {

        addDocument();

        return getResult(true);
    }

    @SneakyThrows
    @Override
    public JSONObject deleteIndex(String indexName) {

        // 创建删除请求 设置index name
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
        // 设置超时时间
        deleteIndexRequest.timeout(TimeValue.timeValueMinutes(2));

        deleteIndexRequest.indicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);


        AcknowledgedResponse delete = null;
        // 创建异步处理
        ActionListener<AcknowledgedResponse> listener = new ActionListener<AcknowledgedResponse>() {
            @Override
            public void onResponse(AcknowledgedResponse acknowledgedResponse) {
                System.out.println("调用成功!");
            }

            @Override
            public void onFailure(Exception e) {
                System.out.println("调用失败!");

            }
        };

        // 使用异步的方式
       // restHighLevelClient.indices().deleteAsync(deleteIndexRequest, RequestOptions.DEFAULT,listener);

        try {
             // 使用异步的方式
            restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
            return getResult(true);
        } catch (ElasticsearchException e) {
            if (e.status() == RestStatus.NOT_FOUND) {
                System.out.println("没有发现对应的索引!!!");
            }
        }

        return getResult(false);
    }

    @Override
    public JSONObject getInfo2(Integer num, Integer size) {

        GetRequest getRequest = new GetRequest("lisi","720920f4-3fdd-4730-8a17-87acb04b293b");

        // 设置不返回上下文
        //getRequest.fetchSourceContext(new FetchSourceContext(false));

        try {
            boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
            System.out.println("exists : " + exists);


            GetResponse documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
            System.out.println(documentFields.getSourceAsString());

            System.out.println(JSONObject.toJSONString(documentFields));


        } catch (IOException e) {
            e.printStackTrace();
        }


        return getResult(true);
    }

    @Override
    public JSONObject updateIndex(String id, String name, String address, String age, String message) {

        UserInfo userInfo = new UserInfo();
        userInfo.setMessage(message)
                .setAddress(address)
                .setAge(age)
                .setName(name);

        // 创建更新请求,并设置索引和id
        UpdateRequest updateRequest = new UpdateRequest("lisi",id);
        updateRequest.doc(JSONObject.toJSONString(userInfo), XContentType.JSON);

        // 调用更新
        UpdateResponse update = null;
        try {
            update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            System.out.println(update.status());
            log.info("修改结果 : " + update.status());
            return getResult(update.status());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return getResult(false);
    }

    @Override
    public JSONObject batchAddDoc() {

        // 批量更新 和 保存
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout(TimeValue.timeValueSeconds(10));
        List<UserInfo> userInfos = Lists.newArrayList();
        userInfos.add(new UserInfo("zhangsan","33","杭州","信息"));
        userInfos.add(new UserInfo("zhangsan2","333","杭州1","信息"));
        userInfos.add(new UserInfo("zhangsan3","3333","杭州2","信息"));
        userInfos.add(new UserInfo("zhangsan4","33333","杭州3","信息"));
        userInfos.add(new UserInfo("zhangsan5","333333","杭州4","信息"));
        userInfos.add(new UserInfo("zhangsan6","3333333","杭州5","信息"));
        userInfos.add(new UserInfo("zhangsan111","33333333","杭州6","信息"));
        userInfos.add(new UserInfo("zhangsan8","333333333","杭州7","信息"));
        userInfos.add(new UserInfo("zhangsan8111","333333333","杭州7","信息"));
        userInfos.add(new UserInfo("zhangsan8331","333333333","杭州7","信息"));

        Snowflake snowflake = new Snowflake(9,9);

        ActionListener actionListener = new ActionListener() {
            @Override
            public void onResponse(Object o) {
                System.out.println("执行成功了!!!");
            }

            @Override
            public void onFailure(Exception e) {
                System.out.println("执行失败了!!!!");
            }
        };

        for (UserInfo userInfo : userInfos) {
            IndexRequest indexRequest = new IndexRequest("lisi")
                    .id(snowflake.nextIdStr())
                    .source(JSONObject.toJSONString(userInfo),XContentType.JSON)
                    ;
            bulkRequest.add(indexRequest);
        }

        BulkResponse bulk = null;
        try {
            bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            // 返回false 代表成功
            System.out.println("执行结果 : " + bulk.hasFailures());
            if (bulk.hasFailures()) {
                System.out.println(bulk.buildFailureMessage());
                System.out.println(JSONObject.toJSONString(bulk));
                return getResult(false);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return getResult(true);
    }

    /**
     * 增加文档信息
     */
    public void addDocument() {
        try {
            // 创建索引请求对象
            IndexRequest indexRequest = new IndexRequest("lisi")
                    .id(UUID.randomUUID().toString());

            // 设置路由
            // indexRequest.routing("routing");
            indexRequest.timeout(TimeValue.timeValueSeconds(2));

            // 设置刷新策略
            indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);


            // 创建员工信息
            UserInfo userInfo = new UserInfo();
            userInfo.setName("lll");
            userInfo.setAge("29");
            userInfo.setAddress("dddd");
            userInfo.setMessage("ffff");

            // 将对象转换为 byte 数组
            String source = JSONObject.toJSONString(userInfo);

            System.out.println(source);
            // 设置文档内容
            indexRequest.source(source, XContentType.JSON);
            // 执行增加文档
            IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT)
                    ;
            log.info("创建状态：{}", response.status());
        } catch (Exception e) {
            log.error("", e);
            e.printStackTrace();
        }
    }

    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    class UserInfo {
        private String name;
        private String age;
        private String address;
        private String message;

    }

    private void handlePage(SearchSourceBuilder sourceBuilder, Integer pageNum, Integer size) {

        int from = (pageNum - 1) * size;
        sourceBuilder.from(from);
        sourceBuilder.size(size);
        // 设置超时时间
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
    }

    private JSONObject getResult(Object data) {

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data", data);

        return jsonObject;
    }


}